﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using IPC.Communication.BasicFramework;
using IPC.Communication.Core;
using IPC.Communication.Core.Address;

namespace IPC.Communication.Profinet.FATEK
{
    public class FatekProgramHelper
    {
        public static string CalculateAcc(string data)
        {
            byte[] bytes = Encoding.ASCII.GetBytes(data);
            int num = 0;
            for (int i = 0; i < bytes.Length; i++)
            {
                num += bytes[i];
            }
            return num.ToString("X4").Substring(2);
        }

        public static OperateResult<List<byte[]>> BuildReadCommand(byte station, string address, ushort length, bool isBool)
        {
            station = (byte)HslHelper.ExtractParameter(ref address, "s", station);
            OperateResult<FatekProgramAddress> operateResult = FatekProgramAddress.ParseFrom(address, length);
            if (!operateResult.IsSuccess)
            {
                return operateResult.ConvertFailed<List<byte[]>>();
            }
            List<byte[]> list = new List<byte[]>();
            int[] array = SoftBasic.SplitIntegerToArray(length, 255);
            for (int i = 0; i < array.Length; i++)
            {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.Append('\u0002');
                stringBuilder.Append(station.ToString("X2"));
                if (isBool)
                {
                    stringBuilder.Append("44");
                    stringBuilder.Append(array[i].ToString("X2"));
                }
                else
                {
                    stringBuilder.Append("46");
                    stringBuilder.Append(array[i].ToString("X2"));
                    if (operateResult.Content.DataCode.StartsWith("X") || operateResult.Content.DataCode.StartsWith("Y") || operateResult.Content.DataCode.StartsWith("M") || operateResult.Content.DataCode.StartsWith("S") || operateResult.Content.DataCode.StartsWith("T") || operateResult.Content.DataCode.StartsWith("C"))
                    {
                        stringBuilder.Append("W");
                    }
                }
                stringBuilder.Append(operateResult.Content.ToString());
                stringBuilder.Append(CalculateAcc(stringBuilder.ToString()));
                stringBuilder.Append('\u0003');
                list.Add(Encoding.ASCII.GetBytes(stringBuilder.ToString()));
                operateResult.Content.AddressStart += array[i];
            }
            return OperateResult.CreateSuccessResult(list);
        }

        public static byte[] ExtraResponse(byte[] response, ushort length)
        {
            byte[] array = new byte[length * 2];
            for (int i = 0; i < array.Length / 2; i++)
            {
                ushort value = Convert.ToUInt16(Encoding.ASCII.GetString(response, i * 4 + 6, 4), 16);
                BitConverter.GetBytes(value).CopyTo(array, i * 2);
            }
            return array;
        }

        public static OperateResult<byte[]> BuildWriteBoolCommand(byte station, string address, bool[] value)
        {
            station = (byte)HslHelper.ExtractParameter(ref address, "s", station);
            OperateResult<FatekProgramAddress> operateResult = FatekProgramAddress.ParseFrom(address, 0);
            if (!operateResult.IsSuccess)
            {
                return operateResult.ConvertFailed<byte[]>();
            }
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append('\u0002');
            stringBuilder.Append(station.ToString("X2"));
            stringBuilder.Append("45");
            stringBuilder.Append(value.Length.ToString("X2"));
            stringBuilder.Append(operateResult.Content.ToString());
            for (int i = 0; i < value.Length; i++)
            {
                stringBuilder.Append(value[i] ? "1" : "0");
            }
            stringBuilder.Append(CalculateAcc(stringBuilder.ToString()));
            stringBuilder.Append('\u0003');
            return OperateResult.CreateSuccessResult(Encoding.ASCII.GetBytes(stringBuilder.ToString()));
        }

        public static OperateResult<byte[]> BuildWriteByteCommand(byte station, string address, byte[] value)
        {
            station = (byte)HslHelper.ExtractParameter(ref address, "s", station);
            OperateResult<FatekProgramAddress> operateResult = FatekProgramAddress.ParseFrom(address, 0);
            if (!operateResult.IsSuccess)
            {
                return operateResult.ConvertFailed<byte[]>();
            }
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append('\u0002');
            stringBuilder.Append(station.ToString("X2"));
            stringBuilder.Append("47");
            stringBuilder.Append((value.Length / 2).ToString("X2"));
            if (operateResult.Content.DataCode.StartsWith("X") || operateResult.Content.DataCode.StartsWith("Y") || operateResult.Content.DataCode.StartsWith("M") || operateResult.Content.DataCode.StartsWith("S") || operateResult.Content.DataCode.StartsWith("T") || operateResult.Content.DataCode.StartsWith("C"))
            {
                stringBuilder.Append("W");
            }
            stringBuilder.Append(operateResult.Content.ToString());
            byte[] array = new byte[value.Length * 2];
            for (int i = 0; i < value.Length / 2; i++)
            {
                SoftBasic.BuildAsciiBytesFrom(BitConverter.ToUInt16(value, i * 2)).CopyTo(array, 4 * i);
            }
            stringBuilder.Append(Encoding.ASCII.GetString(array));
            stringBuilder.Append(CalculateAcc(stringBuilder.ToString()));
            stringBuilder.Append('\u0003');
            return OperateResult.CreateSuccessResult(Encoding.ASCII.GetBytes(stringBuilder.ToString()));
        }

        public static OperateResult CheckResponse(byte[] content)
        {
            if (content[0] != 2)
            {
                return new OperateResult(content[0], "Write Faild:" + SoftBasic.ByteToHexString(content, ' '));
            }
            if (content[5] != 48)
            {
                return new OperateResult(content[5], GetErrorDescriptionFromCode((char)content[5]));
            }
            return OperateResult.CreateSuccessResult();
        }

        public static string GetErrorDescriptionFromCode(char code)
        {
            switch (code)
            {
                case '2':
                    return StringResources.Language.FatekStatus02;
                case '3':
                    return StringResources.Language.FatekStatus03;
                case '4':
                    return StringResources.Language.FatekStatus04;
                case '5':
                    return StringResources.Language.FatekStatus05;
                case '6':
                    return StringResources.Language.FatekStatus06;
                case '7':
                    return StringResources.Language.FatekStatus07;
                case '9':
                    return StringResources.Language.FatekStatus09;
                case 'A':
                    return StringResources.Language.FatekStatus10;
                default:
                    return StringResources.Language.UnknownError;
            }
        }

        public static OperateResult<byte[]> Read(IReadWriteDevice device, byte station, string address, ushort length)
        {
            OperateResult<List<byte[]>> operateResult = BuildReadCommand(station, address, length, isBool: false);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<byte[]>(operateResult);
            }
            List<byte> list = new List<byte>();
            int[] array = SoftBasic.SplitIntegerToArray(length, 255);
            for (int i = 0; i < operateResult.Content.Count; i++)
            {
                OperateResult<byte[]> operateResult2 = device.ReadFromCoreServer(operateResult.Content[i]);
                if (!operateResult2.IsSuccess)
                {
                    return OperateResult.CreateFailedResult<byte[]>(operateResult2);
                }
                OperateResult operateResult3 = CheckResponse(operateResult2.Content);
                if (!operateResult3.IsSuccess)
                {
                    return operateResult3.ConvertFailed<byte[]>();
                }
                list.AddRange(ExtraResponse(operateResult2.Content, (ushort)array[i]));
            }
            return OperateResult.CreateSuccessResult(list.ToArray());
        }

        //[AsyncStateMachine(typeof(<ReadAsync>d__8))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult<byte[]>> ReadAsync(IReadWriteDevice device, byte station, string address, ushort length)
        //{
        //    <ReadAsync>d__8 stateMachine = new <ReadAsync>d__8();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
        //    stateMachine.device = device;
        //    stateMachine.station = station;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public static OperateResult Write(IReadWriteDevice device, byte station, string address, byte[] value)
        {
            OperateResult<byte[]> operateResult = BuildWriteByteCommand(station, address, value);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = device.ReadFromCoreServer(operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            OperateResult operateResult3 = CheckResponse(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return operateResult3;
            }
            return OperateResult.CreateSuccessResult();
        }

        //[AsyncStateMachine(typeof(<WriteAsync>d__10))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult> WriteAsync(IReadWriteDevice device, byte station, string address, byte[] value)
        //{
        //    <WriteAsync>d__10 stateMachine = new <WriteAsync>d__10();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.device = device;
        //    stateMachine.station = station;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public static OperateResult<bool[]> ReadBool(IReadWriteDevice device, byte station, string address, ushort length)
        {
            OperateResult<List<byte[]>> operateResult = BuildReadCommand(station, address, length, isBool: true);
            if (!operateResult.IsSuccess)
            {
                return OperateResult.CreateFailedResult<bool[]>(operateResult);
            }
            List<bool> list = new List<bool>();
            int[] array = SoftBasic.SplitIntegerToArray(length, 255);
            for (int i = 0; i < operateResult.Content.Count; i++)
            {
                OperateResult<byte[]> operateResult2 = device.ReadFromCoreServer(operateResult.Content[i]);
                if (!operateResult2.IsSuccess)
                {
                    return OperateResult.CreateFailedResult<bool[]>(operateResult2);
                }
                OperateResult operateResult3 = CheckResponse(operateResult2.Content);
                if (!operateResult3.IsSuccess)
                {
                    return operateResult3.ConvertFailed<bool[]>();
                }
                list.AddRange(from m in operateResult2.Content.SelectMiddle(6, array[i])
                              select m == 49);
            }
            return OperateResult.CreateSuccessResult(list.ToArray());
        }

        //[AsyncStateMachine(typeof(<ReadBoolAsync>d__12))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult<bool[]>> ReadBoolAsync(IReadWriteDevice device, byte station, string address, ushort length)
        //{
        //    <ReadBoolAsync>d__12 stateMachine = new <ReadBoolAsync>d__12();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool[]>>.Create();
        //    stateMachine.device = device;
        //    stateMachine.station = station;
        //    stateMachine.address = address;
        //    stateMachine.length = length;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}

        public static OperateResult Write(IReadWriteDevice device, byte station, string address, bool[] value)
        {
            OperateResult<byte[]> operateResult = BuildWriteBoolCommand(station, address, value);
            if (!operateResult.IsSuccess)
            {
                return operateResult;
            }
            OperateResult<byte[]> operateResult2 = device.ReadFromCoreServer(operateResult.Content);
            if (!operateResult2.IsSuccess)
            {
                return operateResult2;
            }
            OperateResult operateResult3 = CheckResponse(operateResult2.Content);
            if (!operateResult3.IsSuccess)
            {
                return operateResult3;
            }
            return OperateResult.CreateSuccessResult();
        }

        //[AsyncStateMachine(typeof(<WriteAsync>d__14))]
        //[DebuggerStepThrough]
        //public static Task<OperateResult> WriteAsync(IReadWriteDevice device, byte station, string address, bool[] value)
        //{
        //    <WriteAsync>d__14 stateMachine = new <WriteAsync>d__14();
        //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
        //    stateMachine.device = device;
        //    stateMachine.station = station;
        //    stateMachine.address = address;
        //    stateMachine.value = value;
        //    stateMachine.<>1__state = -1;
        //    stateMachine.<>t__builder.Start(ref stateMachine);
        //    return stateMachine.<>t__builder.Task;
        //}
    }
}